package cn.icanci.loopstack.bic.biz.adapter;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.annotation.Resource;

import org.apache.commons.text.StringSubstitutor;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import cn.hutool.json.JSONUtil;
import cn.icanci.loopstack.bic.biz.exception.GraphAdapterException;
import cn.icanci.loopstack.bic.biz.service.*;
import cn.icanci.loopstack.bic.common.model.base.EdgeStyleVO;
import cn.icanci.loopstack.bic.common.model.base.NodeStyleVO;
import cn.icanci.loopstack.bic.common.model.base.NodeVO;
import cn.icanci.loopstack.bic.common.model.base.NodeVueVO;
import cn.icanci.loopstack.bic.common.model.graph.UnitEdgeVO;
import cn.icanci.loopstack.bic.common.model.graph.UnitNodeVO;
import cn.icanci.loopstack.bic.common.model.graph.UnitViewVO;
import cn.icanci.loopstack.bic.graph.Graph;
import cn.icanci.loopstack.bic.graph.edge.Edge;
import cn.icanci.loopstack.bic.graph.node.Node;

/**
 * @author icanci
 * @since 1.0 Created in 2023/09/22 20:46
 */
@Service
public class GraphAdapterService implements GraphAdapter {
    @Resource
    private UnitViewService  unitViewService;
    @Resource
    private NodeService      nodeService;
    @Resource
    private NodeVueService   nodeVueService;
    @Resource
    private NodeStyleService nodeStyleService;
    @Resource
    private EdgeStyleService edgeStyleService;

    @Override
    public Graph graph(String systemUuid, String useCaseUuid) {
        // 查询结构图
        UnitViewVO unitView = unitViewService.queryBySystemUuidAndUseCaseUuid(systemUuid, useCaseUuid);
        if (unitView == null) {
            throw new GraphAdapterException("纠察图不存在");
        }
        List<UnitEdgeVO> edges = unitView.getEdges();
        List<UnitNodeVO> nodes = unitView.getNodes();
        return new Graph(adapterEdges(edges), adapterNodes(nodes));
    }

    private List<Node> adapterNodes(List<UnitNodeVO> nodes) {
        List<Node> retNodes = Lists.newArrayList();
        for (UnitNodeVO node : nodes) {
            retNodes.add(buildNode(node));
        }
        return retNodes;
    }

    private Node buildNode(UnitNodeVO node) {
        String nodeUuid = node.getNodeUuid();
        String styleUuid = node.getStyleUuid();
        NodeVO nodeVO = nodeService.queryByUuid(nodeUuid);
        String nodeStyle = Optional.ofNullable(nodeStyleService.queryByUuid(styleUuid)).map(NodeStyleVO::getNodeStyle).orElse(nodeStyleService.loadDefaultStyle());
        StringSubstitutor sub = new StringSubstitutor(buildNodeMap(nodeVO));
        nodeStyle = sub.replace(nodeStyle);
        Node retNode = JSONUtil.toBean(nodeStyle, Node.class);
        retNode.setNodeDataMode(node.getNodeDataMode().getCode());
        retNode.setNodeDataKey(node.getNodeDataKey());
        retNode.setNodeType(node.getNodeType().getCode());
        NodeVueVO nodeVueVO = nodeVueService.queryByUuid(node.getNodeVue());
        retNode.setNodeVueCode(nodeVueVO.getNodeVueCode());
        retNode.setNodeVueType(nodeVueVO.getNodeVueType().getCode());
        return retNode;
    }

    private Map<String, String> buildNodeMap(NodeVO node) {
        Map<String, String> nodeMap = Maps.newHashMap();
        nodeMap.put("nodeId", node.getUuid());
        nodeMap.put("nodeName", node.getNodeName());
        return nodeMap;
    }

    private List<Edge> adapterEdges(List<UnitEdgeVO> edges) {
        List<Edge> retEdges = Lists.newArrayList();
        for (UnitEdgeVO edge : edges) {
            retEdges.add(buildEdge(edge));
        }
        return retEdges;
    }

    private Edge buildEdge(UnitEdgeVO edge) {
        String styleUuid = edge.getStyleUuid();
        String edgeStyle = Optional.ofNullable(edgeStyleService.queryByUuid(styleUuid)).map(EdgeStyleVO::getEdgeStyle).orElse(edgeStyleService.loadDefaultStyle());
        StringSubstitutor sub = new StringSubstitutor(buildEdgeMap(edge));
        edgeStyle = sub.replace(edgeStyle);
        Edge retEdge = JSONUtil.toBean(edgeStyle, Edge.class);
        retEdge.setDeep(edge.getDeep());
        return retEdge;
    }

    private Map<String, String> buildEdgeMap(UnitEdgeVO edge) {
        HashMap<String, String> edgeMap = Maps.newHashMap();
        edgeMap.put("sourceId", edge.getSourceUuid());
        edgeMap.put("targetId", edge.getTargetUuid());
        edgeMap.put("hoverName", edge.getHoverName());
        return edgeMap;
    }
}
